package jeesample.service.impl;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import jeesample.dao.OrmLiteManager;
import jeesample.model.Booking;
import jeesample.model.Room;
import jeesample.service.RoomBookingService;

import org.apache.log4j.Logger;

import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.stmt.QueryBuilder;

public class RoomBookingImpl extends BaseServiceImpl implements
		RoomBookingService {
	static {
		logger = Logger.getLogger(RoomBookingImpl.class);
	}

	private Dao<Room, Integer> roomDao;
	private Dao<Booking, Integer> bookingDao;

	public RoomBookingImpl() {
		try {
			roomDao = DaoManager.createDao(
					OrmLiteManager.getConnectionSource(), Room.class);
		} catch (SQLException e) {
			err("Failure to create Room Dao.", e);
		}
		try {
			bookingDao = DaoManager.createDao(
					OrmLiteManager.getConnectionSource(), Booking.class);
		} catch (SQLException e) {
			err("Failure to create Booking Dao.", e);
		}
	}

	@Override
	public List<Booking> getRoomsBooked() {
		List<Booking> roomsBooked = new LinkedList<>();
		try {
			List<Booking> bookings = bookingDao.queryForAll();
			dbg("Total booking:" + bookings.size());
			if (bookings.isEmpty()) {
				return roomsBooked;
			}
			roomsBooked=bookings; 
		} catch (SQLException e) {
			err("Failure to check if a room is booked.", e);
			return roomsBooked;
		}
		dbg("Total booked room:" + roomsBooked.size());
		return roomsBooked;
	}

	@Override
	public List<Room> getRoomsAvailable() {
		List<Room> roomsAvail = new LinkedList<>();
		List<Room> rooms;
		try {
			rooms = roomDao.queryForAll();
			dbg("Total room:" + rooms.size());
			if (rooms.isEmpty()) {
				return roomsAvail;
			}
			
		} catch (SQLException e) {
			err("Failure to check if a room is booked.", e);
			return roomsAvail;
		}
		try {
			List<Booking> bookings = bookingDao.queryForAll();
			dbg("Total booking:" + bookings.size());
			if (bookings.isEmpty()) {
				return rooms;
			}
			for (Room room : rooms) {
				String roomId = room.getRoomId();
				boolean isBooked = false;
				for (Booking booking : bookings) {
					if (booking.getRoomId().equalsIgnoreCase(roomId)) {
						isBooked = true;
						break;
					}
				}
				if (isBooked == false) {
					roomsAvail.add(room);
				}
			}
		} catch (SQLException e) {
			err("Failure to check if a room is booked.", e);
			return roomsAvail;
		}
		dbg("Total available room:" + roomsAvail.size());
		return roomsAvail;
	}

	@Override
	public Booking reserve(Booking booking) {
		String roomId = booking.getRoomId();
		long count = 0;
		// check to see if there is any reservation.
		QueryBuilder<Booking, Integer> qry = bookingDao.queryBuilder();
		try {
			qry.where().eq(Booking.ROOMID, roomId).and()
					.ge(Booking.STARTTIME, booking.getStartTime()).and()
					.le(Booking.ENDTIME, booking.getEndTime());
			qry.setCountOf(true); // needed to ensure the counting works.
			count = bookingDao.countOf(qry.prepare());
		} catch (SQLException e) {
			err("Failure to check if a room is booked.", e);
			return null;
		}
		booking.setRoomId(roomId);
		if (count > 0) {
			booking.setComments("Room already been booked.");
			return booking;
		}
		try {
			dbg("create a new booking:" + booking.getBookingId());
			return bookingDao.createIfNotExists(booking);
		} catch (SQLException e) {
			err("Failure to save new booking.", e);
			return null;
		}
	}

	@Override
	public Room unreserve(Booking booking) {
		QueryBuilder<Booking, Integer> qry1 = bookingDao.queryBuilder();
		try {
			qry1.where().eq(Booking.BOOKINGID, booking.getBookingId());
			List<Booking> bookings = bookingDao.query(qry1.prepare());
			if (bookings.isEmpty()) {
				return null;
			}
			booking = bookings.get(0);
		} catch (SQLException e) {
			err("Failure to check if there is a booking.", e);
			return null;
		}

		String roomId = booking.getRoomId();
		Room room = null;
		QueryBuilder<Room, Integer> qry2 = roomDao.queryBuilder();
		try {
			qry2.where().eq(Room.ROOMID, roomId);
			List<Room> rooms = roomDao.query(qry2.prepare());
			if (rooms.isEmpty()) {
				return null;
			}
			room = rooms.get(0);
		} catch (SQLException e) {
			err("Failure to find room information.", e);
		}

		DeleteBuilder<Booking, Integer> delete = bookingDao.deleteBuilder();
		try {
			delete.where().eq(Booking.BOOKINGID, booking.getBookingId());
			long cnt = bookingDao.delete(delete.prepare());
			if (cnt > 0) {
				dbg("removed the existing booking:" + booking.getBookingId());
			}
		} catch (SQLException e) {
			err("Failure to unreserve booking.", e);
			return null;
		}

		return room;
	}

}
